﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
//.NET socket libraries
using System.Net;
using System.Net.Sockets;
//for threading inclu threads safe method
using System.Threading;
using System.Net.NetworkInformation;
using System.Diagnostics;



namespace EITSurferInfinityLib
{
    public class Swisstom0 : IDriver 
    {
        int IQSize;
        int IQ2Size;  //injection electrode voltage

        FramesWriter fw;

        SimpleDataEvent OnSimpleData;
        RawDataFramesEvent OnRawDataFrames;
        RawDataEvent OnRawData;
        MessageEvent OnMessage;
        ConnectedEvent OnConnected;

        protected Ethernet DataPort;
        protected Ethernet MsgPort;

        protected String IPAddress;
        protected string PreviousDeviceIP;
        protected bool Connected;
        protected bool DeviceDetected;

        protected int DataSize;

        protected int code;
        string messaging ;


        //helper.OnConnected += new EthernetHelper.OnConnectedHandler(helper_OnConnected);

        //int code;

        bool FireEventsDataMsg;

        public Swisstom0()
        {
            DataPort = new Ethernet();
            MsgPort = new Ethernet();


            ApplyDefaultPort();
            PreviousDeviceIP = "";
            Connected = false;
            code = 0;
            FireEventsDataMsg = true;
            //fw = new FramesWriter();
            messaging = "";
        }

        void MsgPort_OnConnectionMessageReceived(object sender, EventArgsMsg e)
        {
            EventArgsMsg arg = new EventArgsMsg("Swisstom0, port:10000", e.Message);
            if (OnMessage != null)
                OnMessage(null, arg);
        }

        void DataPort_OnConnectionMessageReceived(object sender, EventArgsMsg e)
        {
            EventArgsMsg arg = new EventArgsMsg("Swisstom0, port:10001", e.Message);
            if (OnMessage != null)
                OnMessage(null, arg);
        }

       

        public void SendConnectionMessage(string s)
        {
            EventArgsMsg arg = new EventArgsMsg("Swisstom0, connection info", s);
            if (OnMessage != null)
                OnMessage(null, arg);
        }

        #region EventImplementation
        event RawDataFramesEvent IDriver.OnRawDataFrames
        {
            add
            {
                if (OnRawDataFrames != null)
                {
                    lock (OnRawDataFrames)
                    {
                        OnRawDataFrames += value;
                    }
                }
                else
                {
                    OnRawDataFrames = new RawDataFramesEvent(value);
                }
            }
            remove
            {
                if (OnRawDataFrames != null)
                {
                    lock (OnRawDataFrames)
                    {
                        OnRawDataFrames -= value;
                    }
                }
            }
        }
        event SimpleDataEvent IDriver.OnSimpleData
        {
            add
            {
                if (OnSimpleData != null)
                {
                    lock (OnSimpleData)
                    {
                        OnSimpleData += value;
                    }
                }
                else
                {
                    OnSimpleData = new SimpleDataEvent(value);
                }
            }
            remove
            {
                if (OnSimpleData != null)
                {
                    lock (OnSimpleData)
                    {
                        OnSimpleData -= value;
                    }
                }
            }
        }
        event RawDataEvent IDriver.OnRawData
        {
            add
            {
                if (OnRawData != null)
                {
                    lock (OnRawData)
                    {
                        OnRawData += value;
                    }
                }
                else
                {
                    OnRawData = new RawDataEvent(value);
                }
            }
            remove
            {
                if (OnRawData != null)
                {
                    lock (OnRawData)
                    {
                        OnRawData -= value;
                    }
                }
            }
        }
        event MessageEvent IDriver.OnMessage
        {
            add
            {
                if (OnMessage != null)
                {
                    lock (OnMessage)
                    {
                        OnMessage += value;
                    }
                }
                else
                {
                    OnMessage = new MessageEvent(value);
                }
            }
            remove
            {
                if (OnMessage != null)
                {
                    lock (OnMessage)
                    {
                        OnMessage -= value;
                    }
                }
            }
        }
        event ConnectedEvent IDriver.OnConnected
        {
            add
            {
                if (OnConnected != null)
                {
                    lock (OnConnected)
                    {
                        OnConnected += value;
                    }
                }
                else
                {
                    OnConnected = new ConnectedEvent(value);
                }
            }
            remove
            {
                if (OnConnected != null)
                {
                    lock (OnConnected)
                    {
                        OnConnected -= value;
                    }
                }
            }
        }

        #endregion

        #region port10000
        private void MsgPort_OnReceived(Object sender, EventArgs e)
        {
            if (FireEventsDataMsg)
            {
                System.Text.Encoding enc = System.Text.Encoding.ASCII;
                byte[] LocalBuffer = MsgPort.DataByte.ToArray();
                MsgPort.DataByte.RemoveRange(0, LocalBuffer.Length);

                string myString = enc.GetString(LocalBuffer);
                //Debug.WriteLine(myString);

                EventArgsMsg arg = new EventArgsMsg("Swisstom0, port:10000", myString);
                if (OnMessage != null)
                    OnMessage(null, arg);
            }
        }

        #endregion

        #region port10001
        private void DataPort_OnReceived(Object sender, EventArgs e)
        {
            if (FireEventsDataMsg)
            {
                code = GetCodeFromDataPacket();
                FillsSizeFromDataPacket();
                if (code < 2)
                {
                    if (DataPort.DataByte.Count >= DataSize)
                    {
                        int DataPacketToRetrieve = (int)(DataPort.DataByte.Count / DataSize);

                         RawDataFrames sd = PopFrames(DataSize, DataPacketToRetrieve);
                         EventArgsRawDataFrames arg = new EventArgsRawDataFrames(sd);

                         if (OnRawDataFrames != null)
                             OnRawDataFrames(null, arg);
                        
                    }
                }
                //switch (code)
                //{
                //    case 0:
                //        //all Data
                //        if (DataPort.DataByte.Count >= DataSize)
                //        {
                //            int DataPacketToRetrieve = (int)(DataPort.DataByte.Count / DataSize);
                //            for (int i = 0; i < DataPacketToRetrieve; i++)
                //            {
                //                SimpleData sd = PopSimpleData();
                //                EventArgsSimpleData arg = new EventArgsSimpleData(sd);

                //                if (OnSimpleData != null)
                //                    OnSimpleData(null, arg);
                //            }
                //        }
                //        break;
                //    case 1:
                //        //all Data
                //        if (DataPort.DataByte.Count >= DataSize)
                //        {
                //            int DataPacketToRetrieve = (int)(DataPort.DataByte.Count / DataSize);
                //            for (int i = 0; i < DataPacketToRetrieve; i++)
                //            {
                //                RawData rd = PopRawData();
                //                EventArgsRawData arg = new EventArgsRawData(rd);

                //                if (OnRawData != null)
                //                    OnRawData(null, arg);
                //            }
                //        }
                //        break;
                //}
            }
        }
        public int GetCodeFromDataPacket()
        {
            int output = -1;
            byte[] buffer=null;

            if (DataPort.DataByte.Count > 3)
            {
                buffer = new byte[4];
                for (int i = 0; i < 4; i++)
                {
                    buffer[i] = DataPort.DataByte[i];
                }
                output = BitConverter.ToInt32(buffer, 0);
            }
            return output ;
        }
        public void FillsSizeFromDataPacket()
        {
            if (DataPort.DataByte.Count != 0)
            {
                byte[] buffer = new byte[4];

                for (int i = 0; i < 4; i++)
                {
                    buffer[i] = DataPort.DataByte[i + 4 * 1];
                }
                DataSize = BitConverter.ToInt32(buffer, 0);

                for (int i = 0; i < 4; i++)
                {
                    buffer[i] = DataPort.DataByte[i + 4 * 10];
                }
                IQSize = BitConverter.ToInt32(buffer, 0);
            }
        }
        public int GetSize()
        {
            Stop();
            Thread.Sleep(100);
            DataPort.ClearBuffer();
            MsgPort.ClearBuffer();
            Start(1);
            int timeout = 20;
            for (int tick = 0; tick < timeout; tick++)
            {
                Thread.Sleep(100);
                if (DataPort.DataByte.Count > 50)
                {
                    tick = timeout+1;
                }
            }

            if (DataPort.DataByte.Count > 50)
            {
                byte[] buffer = new byte[4];
                for (int i = 0; i < 4; i++)
                {
                    buffer[i] = DataPort.DataByte[i + 4];
                }
                DataSize = BitConverter.ToInt32(buffer, 0);

                for (int i = 0; i < 4; i++)
                {
                    buffer[i] = DataPort.DataByte[i + 4 * 9];
                }
                IQ2Size = BitConverter.ToInt32(buffer, 0);

                for (int i = 0; i < 4; i++)
                {
                    buffer[i] = DataPort.DataByte[i + 4 * 10];
                }
                IQSize = BitConverter.ToInt32(buffer, 0);
            }
            return DataSize;
        }
        public string GetDataHeader()
        {
            FireEventsDataMsg = false;
            string s = "";
            Stop();
            Thread.Sleep(100);
            DataPort.ClearBuffer();
            MsgPort.ClearBuffer();
            Start(1);
            Thread.Sleep(100);
            byte[] buffer = new byte[4];
            for (int j = 0; j < 12; j++)
            {
                for (int i = 0; i < 4; i++)
                {
                    buffer[i] = DataPort.DataByte[i + j * 4];
                }
                s += BitConverter.ToInt32(buffer, 0).ToString() + '\n';
            }
            FireEventsDataMsg = true;
            return s;
        }
        public string GetCode()
        {
            FireEventsDataMsg = false;
            string s = "";
            Stop();
            Thread.Sleep(200);
            DataPort.ClearBuffer();
            MsgPort.ClearBuffer();
            Start(1);
            for (int i = 0; i < 10; i++)
            {
                Thread.Sleep(100);
                s = GetCodeFromDataPacket().ToString();
                if (s != "-1")
                {
                    i = 11;
                }
            }
            DataPort.ClearBuffer();
            MsgPort.ClearBuffer();
            FireEventsDataMsg = true;
            return s;
        }
        private string GetFirmwareInfo()
        {
            FireEventsDataMsg = false;
            string s = "";
            Stop();
            Thread.Sleep(100);
            DataPort.ClearBuffer();
            MsgPort.ClearBuffer();
            Thread.Sleep(100);
            Send("Version");
            byte[] LocalBuffer=null;
            for (int i = 0; i < 10; i++)
            {
                Thread.Sleep(100);
                System.Text.Encoding enc = System.Text.Encoding.ASCII;
                LocalBuffer = MsgPort.DataByte.ToArray();
                s = enc.GetString(LocalBuffer);
                string [] splitstring = s.Split('\n');
                int firmwareNameIndex=0;
                for (int j = 0; j < splitstring.Length; j++)
                {
                    if (splitstring[j].Contains("SBC"))
                    {
                        i = 11;
                        firmwareNameIndex = j;
                    }
                }
                s = splitstring[firmwareNameIndex];
            }
            MsgPort.DataByte.RemoveRange(0, LocalBuffer.Length);
            DataPort.ClearBuffer();
            MsgPort.ClearBuffer();
            FireEventsDataMsg = true;
            return s;
        }
        #endregion

        #region DataHandling
        private RawDataFrames PopFrames(int size, int count)
        {
            if (size > 0)
            {
                RawDataFrames data = new RawDataFrames();
                for (int i = 0; i < count; i++)
                {
                    data.data.Add(new byte[size]);
                    DataPort.DataByte.CopyTo(i * size, data.data[i], 0, size);
                }
                DataPort.DataByte.RemoveRange(0, DataSize);

                return data;
            }
            else
            {
                Send("stop");
                Reset();
                Send("start");
                Debug.WriteLine("PopFrame: negative size");
                return new RawDataFrames();
            }
        }
        //private SimpleData PopSimpleData()
        //{
        //    SimpleData sd = new SimpleData(IQSize/8, IQ2Size/8);
        //    byte[] buffer = new byte[4];

        //    int IQ2Pointer = 12 * 4;
        //    int IQPointer = IQ2Pointer + IQ2Size;

        //    for (int i = 0; i < (IQ2Size / 8); i++)
        //    {
        //        for (int j = 0; j < 4; j++)
        //        {
        //            buffer[j] = DataPort.DataByte[j + 8 * i + IQ2Pointer];
        //        }
        //        sd.I2[i] = BitConverter.ToInt32(buffer, 0);

        //        for (int j = 0; j < 4; j++)
        //        {
        //            buffer[j] = DataPort.DataByte[j+4 + 8 * i + IQ2Pointer];
        //        }
        //        sd.Q2[i] = BitConverter.ToInt32(buffer, 0);
        //    }

        //    for (int i = 0; i < (IQSize / 8); i++)
        //    {
        //        for (int j = 0; j < 4; j++)
        //        {
        //            buffer[j] = DataPort.DataByte[j + 8 * i + IQPointer];
        //        }
        //        sd.I[i] = BitConverter.ToInt32(buffer, 0);

        //        for (int j = 0; j < 4; j++)
        //        {
        //            buffer[j] = DataPort.DataByte[j+4 + 8 * i + IQPointer];
        //        }
        //        sd.Q[i] = BitConverter.ToInt32(buffer, 0);
        //    }
        //    byte[] temp = new byte[DataSize];
        //    DataPort.DataByte.CopyTo(0,temp,0,DataSize);
        //    //fw.Add(temp);
        //    DataPort.DataByte.RemoveRange(0, DataSize);

        //    return sd;
        //}

        //private RawData PopRawData()
        //{
        //    int B= 2;
        //    int B2 = 2*B;


        //    RawData rd = new RawData(IQSize / B2);

        //    byte[] buffer = new byte[B];

        //    int RawPointer = 12 * 4;

        //    for (int i = 0; i < (IQSize / B2); i++)
        //    {
        //        for (int j = 0; j < B; j++)
        //        {
        //            buffer[j] = DataPort.DataByte[j + B2 * i + RawPointer];
        //        }
        //        if (B == 2)
        //        {
        //            rd.Signal1[i] = BitConverter.ToInt16(buffer, 0);
        //        }
        //        else
        //        {
        //            //rd.Signal1[i] = BitConverter.ToInt32(buffer, 0);
        //        }

        //        for (int j = 0; j < B; j++)
        //        {
        //            buffer[j] = DataPort.DataByte[j+B + B2 * i + RawPointer];
        //        }

        //        if (B == 2)
        //        {
        //            rd.Signal2[i] = BitConverter.ToInt16(buffer, 0);
        //        }
        //        else
        //        {
        //           // rd.Signal2[i] = BitConverter.ToInt32(buffer, 0);
        //        }
        //    }
        //    DataPort.DataByte.RemoveRange(0, DataSize);
        //    return rd;
        //}

        #endregion

        #region Connection
        public void ConnectP2P()
        {
            IPAddress = "192.168.1.254";
            DeviceDetected = true;
            ConnectAllPort();
        }
        public  void ConnectAllPort()
        {
            bool ConnectionSuccessful = false;
            DataPort = new Ethernet();
            MsgPort = new Ethernet();
            DataPort.OnConnectionMessageReceived += new Ethernet.OnConnectionMessageReceivedHandler(DataPort_OnConnectionMessageReceived);
            MsgPort.OnConnectionMessageReceived += new Ethernet.OnConnectionMessageReceivedHandler(MsgPort_OnConnectionMessageReceived);
            //IPAddress = "138.131.49.39";
            DataPort.SetIPAddress(IPAddress);
            MsgPort.SetIPAddress(IPAddress);
            ApplyDefaultPort();

            if (DeviceDetected)
            {
                if (ConnectAPort(ref MsgPort))
                {
                    PreviousDeviceIP = IPAddress;
                    if (ConnectAPort(ref DataPort))
                    {
                        SendConnectionMessage("DEVICE is CONNECTED!");
                        Debug.WriteLine("DEVICE is CONNECTED!");
                        ConnectionSuccessful = true;

                        GetSize();
                        Stop();
                        DataPort.ClearBuffer();
                        MsgPort.ClearBuffer();

                        Thread.Sleep(300);

                        DataPort.OnReceived += new Ethernet.OnReceivedHandler(DataPort_OnReceived);
                        MsgPort.OnReceived += new Ethernet.OnReceivedHandler(MsgPort_OnReceived);
                        DataPort.OnConnectionMessageReceived += new Ethernet.OnConnectionMessageReceivedHandler(DataPort_OnConnectionMessageReceived);
                        MsgPort.OnConnectionMessageReceived += new Ethernet.OnConnectionMessageReceivedHandler(MsgPort_OnConnectionMessageReceived);

                        if ((OnConnected != null) && ConnectionSuccessful)
                            OnConnected(null, null);
                    }
                }
            }

            
        }
        public bool ConnectAPort(ref Ethernet myPort)
        {
            bool r = true;
            try
            {
                if (myPort != null)
                {
                    myPort.Connect();
                    SendConnectionMessage("Connected To: " + myPort.ToString());
                    Debug.WriteLine("Connected To: " + myPort.ToString());
                }
            }
            catch (Exception e)
            {
                r = false;
                Debug.WriteLine(e);
            }
            return r;
        }
        #endregion

        public void Reset()
        {
            Thread.Sleep(200);//do not delete is required for waiting the device finish writing in buffers or whatever
            DataPort.ClearBuffer();
            MsgPort.ClearBuffer();
            Thread.Sleep(100);
        }

        public DeviceInfo GetDeviceInfo()
        {
            DeviceInfo di = new DeviceInfo();
            di.Manufacturer = "Swisstom";
            di.ConnectionType = "ethernet";
            di.DeviceName = "Swisstom BB1";
            di.IPAddress="";
            di.Protocol = "";
            di.FirmwareVersion = "";
            if (MsgPort.IsConnected())
            {
                di.FirmwareVersion = GetFirmwareInfo();
                di.IPAddress=MsgPort.IPName.ToString();
                di.Protocol = GetCode();
            }
            return di;
        }
        //string ss = "";
        //protected override void helper_OnConnectionMessage(object sender, EventArgsMsg e)
        //{
        //    //this.Dispatcher.Invoke((Action)(() =>
        //    //{
        //    //    SendConnectionMessage(e.Message);
        //    //}));
        //    //System.Threading.Thread.Sleep(100);
        //    //ss+=e.Message;
        //    //base.helper_OnConnectionMessage(sender, e);
        //}
                protected void ProgramParameter(string[] ParameterName, string [] Values)
        {
            if (IsConnected())
            {
                int length=ParameterName.Length;
                for (int i = 0; i < length; i++)
                {
                    Send("set" + ParameterName[i] + Values[i]+"\n");
                }
            }
            else
            {
                Debug.WriteLine("NOT CONNECTED");
            }
        }


        #region port10000
        public void ConnectEventMsgPort()
        { }
        public void Send(string s)
        {
            MsgPort.Send(s);
        }
        #endregion

        #region port10001
        public void ConnectEventDataPort()
        { }
        public void PullOneFrame()
        {
            //writes directly into the DataManager
        }
        //public int GetCode()
        //{
        //    Stop();
        //    Thread.Sleep(100);
        //    DataPort.ClearBuffer();
        //    MsgPort.ClearBuffer();
        //    Start(1);
        //    Thread.Sleep(100);
        //    byte[] buffer = new byte[4];
        //    for (int i = 0; i < 4; i++)
        //    {
        //        buffer[i] = DataPort.DataByte[i];
        //    }

        //    code = BitConverter.ToInt32(buffer, 0);

        //    Debug.WriteLine("code is:" + code.ToString());
        //    return code;
        //}
        #endregion

        #region commands

        public void Start()
        {
            Send("start");
        }

        public void Start(int NumberFrame)
        {
            Send("start " + NumberFrame.ToString());
        }

        public void Stop()
        {
            Send("stop");
        }

        #endregion

        #region Connection
        protected void ApplyDefaultPort()
        {
            DataPort.Port = 10001;
            MsgPort.Port = 10000;
        }
        protected void AutoDetect()
        {
            EthernetHelper helper = new EthernetHelper("192.168.1.254");
            helper.TestText = "SBC";
            helper.TestType = "Contains";
            helper.OnConnected += new EthernetHelper.OnConnectedHandler(helper_OnConnected);
            helper.OnConnectionMessage += new EthernetHelper.OnConnectionMessageHandler(helper_OnConnectionMessage);
            helper.OnConnectionStarting += new EthernetHelper.OnConnectionStartingHandler(helper_OnConnectionStarting);
            helper.OnConnectionStopped += new EthernetHelper.OnConnectionStoppedHandler(helper_OnConnectionStopped);
            helper.AutoDetect();
        }


        void helper_OnConnectionStopped(object sender, EventArgsMsg e)
        {
            EventArgsMsg arg = new EventArgsMsg("Close Alert", "");
            if (OnMessage != null)
                OnMessage(null, arg);
            SendConnectionMessage(messaging);
        }

        void helper_OnConnectionStarting(object sender, EventArgsMsg e)
        {
            EventArgsMsg arg = new EventArgsMsg("Open Alert", "System is Searching a Device... Please wait\r");
            if (OnMessage != null)
                OnMessage(null, arg);
            messaging = "";
        }
        
        void helper_OnConnectionMessage(object sender, EventArgsMsg e)
        {
            messaging += e.Message;
        }
        protected void helper_OnConnected(Object sender, EventArgsMsg e)
        {
            EventArgsMsg arg = new EventArgsMsg("Close Alert", "");
            if (OnMessage != null)
                OnMessage(null, arg);

            IPAddress = e.Message;
            DeviceDetected = true;
            ConnectAllPort();
        }
        public bool IsConnected()
        {
            if (MsgPort.IsConnected() && DataPort.IsConnected())
            {
                return true;
            }
            else
            {
                return false;
            }
        }
        public void Connect()
        {
            AutoDetect();
        }
        //public virtual bool ConnectAPort(ref Ethernet myPort)
        //{
        //    bool r = true;
        //    try
        //    {
        //        if (myPort != null)
        //        {
        //            myPort.Connect();

        //            Debug.WriteLine("Connected To: " + myPort.ToString());
        //        }
        //    }
        //    catch (Exception e)
        //    {
        //        r = false;
        //        Debug.WriteLine(e);
        //    }
        //    return r;
        //}
        //public virtual void ConnectP2P()
        //{
        //    IPAddress = "192.168.1.254";
        //    DeviceDetected = true;
        //    ConnectAllPort();
        //}
        public void Disconnect()
        {
            Debug.WriteLine("start debug");
            if (MsgPort != null && MsgPort.IsConnected())
            {
                MsgPort.Disconnect();
                Debug.WriteLine("Msg port disconnected");
            }
            if (DataPort != null && DataPort.IsConnected())
            {
                DataPort.Disconnect();
                Debug.WriteLine("data port diconnected");
            }
        }
        //public virtual  void ConnectAllPort()
        //{
        //    DataPort = new Ethernet();
        //    MsgPort = new Ethernet();
            
        //    DataPort.SetIPAddress(IPAddress);
        //    MsgPort.SetIPAddress(IPAddress);
        //    ApplyDefaultPort();

        //    if (DeviceDetected)
        //    {
        //        if (ConnectAPort(ref MsgPort))
        //        {
        //            PreviousDeviceIP = IPAddress;
        //            if (ConnectAPort(ref DataPort))
        //            {
        //                Debug.WriteLine("DEVICE is CONNECTED!");
        //            }
        //        }
        //    }


        //    DataPort.OnReceived += new Ethernet.OnReceivedHandler(DataPort_OnReceived);
        //    MsgPort.OnReceived += new Ethernet.OnReceivedHandler(MsgPort_OnReceived);

        //}

        //private void DataPort_OnReceived(Object sender, EventArgs e)
        //{

        //}
        //private void MsgPort_OnReceived(Object sender, EventArgs e)
        //{

        //}


    }
        #endregion
    
        
}
